﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace EngineOfEvermore.Common
{

    public class FrameUpdater
    {
        #region Variables
        int _targetFps = 0;
        double _inverseTargetFps;
        double _timeAccu = 0.0;
        double _lastTime = 0.0;
        ModifiableLogicUpdateEventArgs _e = new ModifiableLogicUpdateEventArgs();
        GorgonLibrary.PreciseTimer _timer = new GorgonLibrary.PreciseTimer();
        #endregion

        #region Properties
        /// <summary>
        /// The target update rate in frames per second.
        /// </summary>
        /// <remarks>
        /// If set to zero the update is executed immediately.
        /// </remarks>
        public int TargetFps
        {
            get { return _targetFps; }
            set
            {
                _targetFps = value;

                if ( _targetFps != 0 )
                {
                    _inverseTargetFps = 1.0 / value;
                    _e.SetIsFixedTimeStep( true );
                    _e.SetElapsedTime( (float)_inverseTargetFps );
                }
                else
                {
                    _e.SetIsFixedTimeStep( false );
                }
            }
        }
        #endregion

        #region Constructor
        public FrameUpdater()
        {
            _timer.HighResolutionTimer = false;
        }
        #endregion

        #region Methods
        public void Update( Action<LogicUpdateEventArgs> updateAction )
        {
            double currentTime = _timer.Seconds;
            double elapsedTime = currentTime - _lastTime;
            _lastTime = currentTime;

            // If there is a target framerate specified only update if necessary
            if ( _targetFps != 0 )
            {
                _timeAccu += elapsedTime;

                while ( _timeAccu > _inverseTargetFps )
                {
                    updateAction( _e );
                    _timeAccu -= _inverseTargetFps;
                }
            }
            else
            {
                // else just propagate the update
                _e.SetElapsedTime( (float)elapsedTime );
                updateAction( _e );
            }
        }
        #endregion
    }
}
